import os
import sys
import time
import copy
import struct
import threading


def _file2list(path):
    lst = []
    fd = open(path, 'r')
    while True:
        str = fd.readline().strip()
        if str == '':
            break
        pair = str.split(':')
        lst.append(pair)
    fd.close()
    return lst

def _file2string(path):
    fd = open(path, 'r')
    str = fd.read()
    fd.close()
    return str

def _system(cmd):
    fd = os.popen(cmd)
    output = fd.read()
    fd.close()
    return output

class _PlatformInfo:

    def __init__(self):
        self.info = {}
        self.get_info()
    
    def add_to_dict(self, key, value):
        self.info[key] = value

    def get_cpu_info(self):
        info = {}
        lst = _file2list('/proc/cpuinfo')

        for items in lst:
            if items[0].startswith('model name'):
                 cpu_model_name = items[1].strip()
        self.add_to_dict('cpu_model_name', cpu_model_name)

        cpu_cores = -1
        lst = _file2list('/proc/stat')
        for elem in lst:
            if elem[0].startswith('cpu'):
                cpu_cores = cpu_cores + 1
        self.add_to_dict('cpu_cores', cpu_cores)

    def get_os_version(self):
        if not os.path.exists('/proc/version'):
		    os_version = 'Other'
        else:
            os_version = _file2string('/proc/version').strip().split('(')[0]
        self.add_to_dict('os_version', os_version)
   
    def get_kernel_version(self):
        kernel_version = _system('/bin/uname -rms').strip()
        self.add_to_dict('kernel_version', kernel_version)
    
    def get_mem_total(self):
        lst = _file2list('/proc/meminfo')
        self.add_to_dict('mem_total',int( lst[0][1].strip()[:-3]) / 1024)
        return True

    def get_info(self):
        self.get_cpu_info()
        self.get_mem_total()
        self.get_os_version()
        self.get_kernel_version()

class _PMDynamicInfo:

    def __init__(self):
        self.info = {}
        self.get_info()
    
    def add_to_dict(self, key, value):
        self.info[key] = value
    
    def get_timestamp(self):
        self.add_to_dict('timestamp', time.time())

    def get_mem_info(self):
        memInfo = []
        memInfoList = _file2list('/proc/meminfo')
        
        for elem in memInfoList:
            if elem[0].startswith('MemFree'):
                memFree = elem[1].strip()
            elif elem[0].startswith('MemTotal'):
                memTotal = elem[1].strip()
        memTotal =int( memTotal[:-3] )
        memFree = int( memFree[:-3]  )
        memData = {'total': memTotal/1024, 'used': (memTotal-memFree)/1024}
        self.add_to_dict('mem', memData)

    def get_cpu_info(self):
        cpuInfo = {}
        cpuStatList = _file2list('/proc/stat')

        for elem in cpuStatList:
            if elem[0].startswith('cpu'):
                dictInfo = {}
                lst = elem[0].split()

                i = 1 
                totalTime = 0
                while i < len(lst):
                    totalTime = totalTime + int(lst[i]) # compute cpu time
                    i = i + 1
                
                dictInfo['total_time'] = float(totalTime)
                usedTime = totalTime - int(lst[4])
                dictInfo['used_time'] = float(usedTime)

                cpuInfo[lst[0]] = dictInfo
            break # remove this line to get core-granu info
        self.add_to_dict('cpu', cpuInfo)

    def get_info(self):
        self.get_mem_info()
        self.get_cpu_info()
        self.get_timestamp()


class Host(object):
    
    def __init__(self, interval = 60):
        #collect interval
        self.click = interval
        #store old dynamic info object
        self.oldinfo = {}
        #store dynamic info
        self.dynamic_info = {'cpu_usage': 0.0, 'mem_usage': 0.0}
        self.static_info = self._get_static()

        producer = threading.Thread(target = self._produce_dynamic_info)
        producer.setDaemon(True)
        producer.start()


    def get_static_info(self):
        return self.static_info

    def get_dynamic_info(self):
        return self.dynamic_info

    def get_info(self):
        s = copy.deepcopy(self.static_info)
        d = copy.deepcopy(self.dynamic_info)
        s.update(d)
        return s

    def _produce_dynamic_info(self):
        while True:
            info = self._get_dynamic()
            cpu_usage = self._get_cpu_usage(self.oldinfo, info)
            mem_usage = self._get_mem_usage(info)
            self.dynamic_info = {'cpu_usage': cpu_usage, 'mem_usage': mem_usage}
            self.oldinfo = info
            time.sleep(self.click)
            print self.get_info()
            

    def _get_cpu_usage(self, old, new):
        try:
            if not old:
                return 0.0
            total = new['cpu']['cpu']['total_time'] -  old['cpu']['cpu']['total_time'] 
            used = new['cpu']['cpu']['used_time'] -  old['cpu']['cpu']['used_time'] 
            usage = float(used) / total
        except:
            usage = 0.0
        return usage

    def _get_mem_usage(self, new):
        try:
            usage = float(new['mem']['used']) / new['mem']['total']
        except:
            usage = 0.0
        return usage


    def _get_static(self):
        try:
            info = _PlatformInfo().info
        except:
            info = {}
        return info


    def _get_dynamic(self):
        try:
            info = _PMDynamicInfo().info
        except:
            raise
            info = {}
        return info




if __name__ == "__main__":
    Host(1)
    while True:
        time.sleep(10)

